package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.dao.DishDao;
import com.itheima.domain.Category;
import com.itheima.domain.Dish;
import com.itheima.domain.DishFlavor;
import com.itheima.domain.SetmealDish;
import com.itheima.dto.DishDto;
import com.itheima.exception.DeleteDishException;
import com.itheima.exception.StopDishException;
import com.itheima.service.CategoryService;
import com.itheima.service.DishFlavorService;
import com.itheima.service.DishService;
import com.itheima.service.SetmealDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishDao, Dish> implements DishService {

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SetmealDishService setmealDishService;

    @Override
    public void saveWithDishFlavor(DishDto dto) {
        //1.往菜品表（dish）添加
        this.save(dto);
        //2.往菜品表（dishflavor）添加
        //dto中的falvors属性，就是往菜品表（dishflavor）中添加的内容
        //因此，我们拿到flavors，遍历，一条一条的插入就可以了

        //2.1
        // 我们往菜品表（dishflavor）添加数据时，有一个属性是dishid，我们需要拿到菜品的id
        // id是在插入菜品表（dish）时通过雪花算法自动生成的，所以上面插入后，我们就可以拿到了
        Long id = dto.getId();
        //2.2，遍历
        List<DishFlavor> flavors = dto.getFlavors();
        for (DishFlavor flavor : flavors) {
            //2.3，id赋值，进行添加
            flavor.setDishId(id);
            dishFlavorService.save(flavor);
        }
    }

    @Override
    public Page selectByPage(int page, int size,String name) {
        /**
         * 我们点击菜品管理时，页面直接发送分页查询请求，查询所有菜品的信息
         * 其他字段都可以在菜品表（dish）中拿到数据，
         * 但是有一个字段“菜品分类”，要求展示的是这个分类的名字-->也就是分类表（category）中的name字段的值
         * 因此我们要返回给页面的数据，就是：分类表的name+菜品表的所有字段
         * 我们的DishDto类就符合我们的需求
         */

        //1.先把dish表中的数据全部拿到
        Page<Dish> pageinfo = new Page<Dish>(page,size);
        LambdaQueryWrapper<Dish> lqw = new LambdaQueryWrapper<>();
        lqw.like(name !=null,Dish::getName,name);
        lqw.orderByDesc(Dish::getUpdateTime);
        this.page(pageinfo, lqw);

        //2.拿到pageinfo中的records属性，该属性就是我们查询dish表得到的数据
        List<Dish> records = pageinfo.getRecords();

        //定义集合,用来存储我们最终整理后的数据
        List<DishDto> list = new ArrayList<>();

        //3.遍历records
        for (Dish record : records) {
            //在遍历过程中，拿到categoryid值，去分类表中通过id查询
            Long categoryId = record.getCategoryId();
            Category category = categoryService.getById(categoryId);

            //把record copy给dishdto
            //把name字段的值，赋给dishdto的categoryname字段
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(record,dishDto);
            dishDto.setCategoryName(category.getName());
            list.add(dishDto);
        }

        //进行整体数据拷贝
        //因为最终我们返回给浏览器的仍然是分页查询内容，因此，我们再创建一个分页构造器，把上面的pageinfo 给copy进来，
        //copy过程中，把原始的records排除掉，用我们自己整理的list集合，赋到records中
        Page<DishDto> dishDtoPage = new Page<>();
        BeanUtils.copyProperties(pageinfo,dishDtoPage,"records");
        dishDtoPage.setRecords(list);
        return dishDtoPage;
    }


    @Override
    public DishDto getByIdWithFlavor(long id) {
        /**
         * 要回显的数据分为两部分：菜品信息，菜品对应的口味信息
         * 因此，我们需要通过查询两张表 dish，dishflavor、
         * 把所有信息封装到dishdto中，返回给前端
         */

        //1.查询菜品表
        Dish dish = this.getById(id);

        //2.查询口味表，
        // 我们要查具体菜品对应的口味，因此需要拿到dishflavor表中的dishid字段，通过id查询
        // dishflavor表中的dishid字段 = dish表中的id字段
        Long dishId = dish.getId();
        LambdaQueryWrapper<DishFlavor> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DishFlavor::getDishId,dishId);
        List<DishFlavor> list = dishFlavorService.list(lqw);

        //把两次查询到的结果，都封装到dishdto中，返回给前端
        DishDto dishDto = new DishDto();
        BeanUtils.copyProperties(dish,dishDto);
        dishDto.setFlavors(list);

        return dishDto;
    }


    @Transactional
    @Override
    public void updateWithFlavor(DishDto dishDto) {
        /**
         * 修改菜品，点击保存后，我们用dishdto接收参数
         * 然后需要把dish表和dishflavor表中的原数据都修改掉，因此需要操作两张表
         */

        //1.修改dish表
        this.updateById(dishDto);

        //2.把dishflavor表中的原数据删除掉(通过dishid删除)
        LambdaQueryWrapper<DishFlavor> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DishFlavor::getDishId,dishDto.getId());
        dishFlavorService.remove(lqw);

        //3.把新的口味数据写到口味表中
        List<DishFlavor> flavors = dishDto.getFlavors();
        for (DishFlavor flavor : flavors) {
            //从前端传过来的数据时，dishid这个属性是没有值的，需要我们自己设置
            flavor.setDishId(dishDto.getId());
            dishFlavorService.save(flavor);
        }
    }

    @Override
    public void MyRemove(List<Long> ids) {
        /**
         * 删除菜品，批量删除菜品
         * 首先要看下这个菜品的状态，如果是起售状态，则抛异常，提示用户先停售再删除
         * 然后还要看这个菜品有没有被套餐关联，如果被套餐关联了，抛异常，提示用户先修改套餐，再来删除
         */
        LambdaQueryWrapper<Dish> lqw = new LambdaQueryWrapper<>();
        lqw.in(Dish::getId,ids);
        List<Dish> list = this.list(lqw);

        for (Dish dish : list) {
            if(dish.getStatus() == 1){
                throw new DeleteDishException("请先停售，再删除");
            }else{
                LambdaQueryWrapper<SetmealDish> lqw2 = new LambdaQueryWrapper<>();
                lqw2.eq(SetmealDish::getDishId,dish.getId());
                int count = setmealDishService.count(lqw2);

                if(count > 0){
                    throw new DeleteDishException("请先修改套餐，再删除");
                }
                this.removeById(dish.getId());
            }
        }
    }

    @Override
    @Transactional
    public void soldAndStop(List<Long> ids) {
        /**
         * 起售，停售
         * 修改之前，先查询一下该菜品有没有和套餐绑定
         * 如果绑定了，就抛异常，并告诉用户先修改套餐信息，再进行停售操作
         */
        for (Long id : ids) {
            LambdaQueryWrapper<SetmealDish> lqw1 = new LambdaQueryWrapper<>();
            lqw1.eq(SetmealDish::getDishId,id);
            int count = setmealDishService.count(lqw1);
            if(count > 0){
                throw new StopDishException("该菜品已被套餐包含，请先修改套餐信息");
            }else{
                Dish dish = this.getById(id);
                if(dish.getStatus() == 0){
                    dish.setStatus(1);
                }else{
                    dish.setStatus(0);
                }
                LambdaQueryWrapper<Dish> lqw2 = new LambdaQueryWrapper<>();
                lqw2.eq(Dish::getId,dish.getId());
                this.update(dish,lqw2);
            }
        }
    }
}